home *** CD-ROM | disk | FTP | other *** search
/ Amiga Developer CD 2.1 / Amiga Developer CD v2.1.iso / Reference / DevCon / Washington_1988 / DevCon88.1 / Assembler / example / example.asm next >
Encoding:
Assembly Source File  |  1992-08-27  |  27.5 KB  |  816 lines

  1.  
  2. ;
  3. ; Copyright (c) 1988 Commodore-Amiga, Inc.
  4. ;
  5. ; Executables based on this information may be used in software
  6. ; for Commodore Amiga computers.  All other rights reserved.
  7. ;
  8. ; This information is provided "as is"; no warranties are made.
  9. ; All use is at your own risk, and no liability or responsibility is assumed.
  10. ;
  11.  
  12. ;==============================================================================
  13. ; An example of Amiga assembly language programming to complement the notes
  14. ; provided for the Developers Conference.  Written by Steve Beats, 4/26/88.
  15. ;
  16. ; This is just a simple letter square program that allows you to slide letters
  17. ; around in a grid with a view to getting them in the right order.  Use the
  18. ; right mouse button to shuffle the letters and the left mouse button to put
  19. ; them back in order again.  A count of shuffles versus moves is kept so you
  20. ; have some idea of how well you are doing.
  21. ;
  22. ; It's left as an excercise for the reader to detect when game is over :-)
  23. ;
  24. ; It would probably be a good idea to re-organise the source into separate,
  25. ; smaller modules, but I left it as one humongous source file so that I didn't
  26. ; have to get bogged down in linker details.  To assemble with the Metacomco
  27. ; assembler, use the following command:-
  28. ;
  29. ;    assem example.asm -o example.o -i INCLUDE: -c=W150000
  30. ;
  31. ; where INCLUDE: is assigned to the directory containing the standard includes.
  32. ; Linking is also simple, just use the following:-
  33. ;
  34. ;    blink example.o to example lib INCLUDE:amiga.lib
  35. ;
  36. ;==============================================================================
  37.         SECTION    example,CODE
  38.  
  39.         NOLIST
  40.         INCLUDE    "exec/types.i"
  41.         INCLUDE    "exec/memory.i"
  42.         INCLUDE    "exec/ports.i"
  43.         INCLUDE    "intuition/intuition.i"
  44.         LIST
  45.  
  46. ; first we define all the global data we will require for this program
  47.     STRUCTURE globals,0
  48.         APTR    SysLib            exec library
  49.         APTR    IntLib            intuition library
  50.         APTR    GfxLib            graphics library
  51.         APTR    DosLib            dos library
  52.  
  53.         APTR    MainWindow        pointer to the window
  54.         LONG    WaitMask        mask of bits to wait for
  55.         APTR    TheRastPort        windows rastport
  56.  
  57.         APTR    GameArray        tile memory
  58.         UWORD    SpaceX            x co-ordinate of the hole
  59.         UWORD    SpaceY            y co-ordinate of the hole
  60.         ULONG    Shuffles        number of shuffles we've done
  61.  
  62.         APTR    TextBuff        for making numbers
  63.         STRUCT  RND,8            current random seed
  64.  
  65.         UWORD    Closed            flag, user hit close gadget
  66.     LABEL globals_SIZEOF
  67.  
  68. ; now define data structures for private stuff used within the program
  69.     STRUCTURE tile,0
  70.         UWORD    t_x            position of tile
  71.         UWORD    t_y
  72.         UWORD    t_type            0=no tile else the letter
  73.         UWORD    t_moved            flag for shuffling
  74.     LABEL tile_SIZEOF
  75.  
  76. ; next, define all library routines we will be calling as external symbols
  77.         XREF    _AbsExecBase,_LVOOpenLibrary,_LVOCloseLibrary
  78.         XREF    _LVOAllocMem,_LVOFreeMem
  79.         XREF    _LVOWait,_LVOGetMsg,_LVOReplyMsg
  80.  
  81.         XREF    _LVOOpenWindow,_LVOCloseWindow
  82.         XREF    _LVOBeginRefresh,_LVOEndRefresh
  83.         XREF    _LVOModifyIDCMP,_LVOCurrentTime
  84.         XREF    _LVODisplayBeep
  85.  
  86.         XREF    _LVOSetAPen,_LVOSetDrMd,_LVOMove
  87.         XREF    _LVOText,_LVORectFill
  88.  
  89. ;==============================================================================
  90. ; The entry point of the program.  Reserve space for globals on the stack.
  91. ;==============================================================================
  92. Start        moveq.l    #(globals_SIZEOF/2)-1,d0
  93. ClrStack    clr.w    -(sp)
  94.         dbra    d0,ClrStack
  95.         movea.l    sp,a5            a5 always points to globals
  96.         move.l    _AbsExecBase,SysLib(a5)    stash exec base
  97.  
  98.         lea.l    Libraries(pc),a0    open all our libraries
  99.         bsr    OpenLibs
  100.         tst.l    d0            did it work ?
  101.         beq    Exit            no, exit now
  102.  
  103.         lea.l    MemTable(pc),a0        allocate all our static memory
  104.         bsr    AllocMemory
  105.         tst.l    d0            did it work ?
  106.         beq    Exit            no, exit now
  107.  
  108.         movea.l    IntLib(a5),a6        seed random number generator
  109.         lea.l    RND(a5),a0
  110.         lea.l    RND+4(a5),a1
  111.         jsr    _LVOCurrentTime(a6)
  112.  
  113.         lea.l    MyWindow(pc),a0        open the window
  114.         move.l    a0,d0
  115.         add.l    d0,nw_Title(a0)        relocate title reference
  116.         jsr    _LVOOpenWindow(a6)
  117.         move.l    d0,MainWindow(a5)    did it open OK ?
  118.         beq    Exit            no, exit now
  119.  
  120.         movea.l    d0,a0            stash important values
  121.         move.l    wd_RPort(a0),TheRastPort(a5)
  122.         moveq.l    #0,d0
  123.         movea.l    wd_UserPort(a0),a1
  124.         move.b    MP_SIGBIT(a1),d1
  125.         bset.l    d1,d0
  126.         move.l    d0,WaitMask(a5)        bit mask we will wait on
  127.  
  128.         bsr    InitTiles        initialise tile memory
  129.         moveq.l    #0,d0            so we redraw OK first time thru
  130.         bsr    RefreshWindow        and draw the tiles
  131.  
  132. ;==============================================================================
  133. ; The main loop of the program.  Wait on some kind of input and dispatch it.
  134. ;==============================================================================
  135. MainLoop    movea.l    SysLib(a5),a6        wait for something to happen
  136.         move.l    WaitMask(a5),d0
  137.         jsr    _LVOWait(a6)
  138.  
  139. NextMessage    movea.l    MainWindow(a5),a0
  140.         movea.l    wd_UserPort(a0),a0    woken up, get a message
  141.         jsr    _LVOGetMsg(a6)
  142.         tst.l    d0
  143.         beq.s    MainLoop        no message, wait again
  144.  
  145.         movea.l    d0,a2            save message pointer
  146.         move.l    im_Class(a2),d0        search table for this class
  147.         lea.l    Dispatch(pc),a0
  148. DispatchLoop    move.l    (a0)+,d1        get function offset
  149.         beq.s    DispatchDone        unknown message!
  150.         cmp.l    (a0)+,d0        was this the correct one ?
  151.         bne.s    DispatchLoop        no, check the next one
  152.  
  153.         movea.l    a2,a0            message to a0 for the routine
  154.         jsr    Dispatch(pc,d1.l)    call correct routine
  155. DispatchDone    movea.l    a2,a1            reply the message
  156.         jsr    _LVOReplyMsg(a6)
  157.         tst.w    Closed(a5)        are we finished ?
  158.         bne.s    Exit            yes
  159.         bra.s    NextMessage        no, look for another message
  160.  
  161. ;==============================================================================
  162. ; a dispatch table containing an offset to a routine and the IDCMP class
  163. ; required for that routine to be called.  Zero terminates the list.
  164. ;==============================================================================
  165. Dispatch    DC.L    HandleClick-Dispatch,MOUSEBUTTONS
  166.         DC.L    RefreshWindow-Dispatch,REFRESHWINDOW
  167.         DC.L    ShuffleOnce-Dispatch,INTUITICKS
  168.         DC.L    CloseDown-Dispatch,CLOSEWINDOW
  169.         DC.L    0
  170.  
  171. ;==============================================================================
  172. ; Program exits here.
  173. ;==============================================================================
  174. Exit        move.l    MainWindow(a5),d0    close window if it opened
  175.         beq.s    Exit_1            no window to close
  176.         movea.l    d0,a0
  177.         movea.l    IntLib(a5),a6        using intuition library
  178.         jsr    _LVOCloseWindow(a6)
  179.  
  180. Exit_1        lea.l    MemTable(pc),a0        free any allocated memory
  181.         bsr    FreeMemory
  182.         lea.l    Libraries(pc),a0    close any opened libraries
  183.         bsr    CloseLibs
  184.         lea.l    globals_SIZEOF(sp),sp    free stack space
  185.         moveq.l    #0,d0            and do a non error return
  186.         rts
  187.  
  188.  
  189. ;==============================================================================
  190. ; CloseDown()
  191. ;
  192. ; Just sets the Closed state variable so we exit the program
  193. ;==============================================================================
  194. CloseDown    move.w    #-1,Closed(a5)
  195.         rts
  196.  
  197. ;==============================================================================
  198. ; RefreshWindow( firsttime )
  199. ;            d0
  200. ;
  201. ; Completely redraws everything in the window, border, tiles and such.  If
  202. ; firsttime == 0 then the Begin and End refresh calls are not made.
  203. ;==============================================================================
  204. RefreshWindow    move.l    a6,-(sp)
  205.         move.l    d0,-(sp)        is this first time
  206.         beq.s    10$            yes, dont beginrefresh
  207.         movea.l    IntLib(a5),a6        using intuition
  208.         movea.l    MainWindow(a5),a0    begin refresh sequence
  209.         jsr    _LVOBeginRefresh(a6)    to fix up layers
  210.  
  211. 10$        bsr    DrawBorder        do the border outline
  212.         bsr    DrawAllTiles        and all the tiles
  213.         bsr    ShuffleCount        and the score area
  214.         move.l    (sp)+,d0        was this first time ?
  215.         beq.s    20$            yes, don't end refresh
  216.  
  217.         movea.l    MainWindow(a5),a0
  218.         jsr    _LVOEndRefresh(a6)    refresh done
  219. 20$        move.l    (sp)+,a6
  220.         rts
  221.  
  222. ;==============================================================================
  223. ; HandleClick( message )
  224. ;         a0
  225. ;
  226. ; Moves a tile based on the position of the given MOUSEBUTTONS message.
  227. ; Left mouse button down will attempt to move the tiles
  228. ; Left mouse button up will do nothing
  229. ; Right mouse button down will start shuffling the tiles (switch on INTUITICKS)
  230. ; Right mouse button up will stop shuffling the tiles (switch off INTUITICKS)
  231. ;==============================================================================
  232. HandleClick    movem.l    a2/a6,-(sp)
  233.         movea.l    a0,a2            stash message address
  234.         move.w    im_Code(a2),d1        check for left or right button
  235.         cmpi.w    #IECODE_LBUTTON!IECODE_UP_PREFIX,d1
  236.         beq.s    ClickDone        nothing for left button up
  237.         cmpi.w    #IECODE_LBUTTON,d1
  238.         beq.s    HandleLeft
  239.  
  240. ; it was a right button click, if down turn on INTUITICKS in the IDCMP port
  241.         move.l    #IDCMPFLAGS!INTUITICKS,d0    assume down
  242.         cmpi.w    #IECODE_RBUTTON!IECODE_UP_PREFIX,d1
  243.         bne.s    10$            assumption correct
  244.         move.l    #IDCMPFLAGS,d0        stop shuffling now
  245. 10$        movea.l    IntLib(a5),a6        using intuition
  246.         movea.l    MainWindow(a5),a0
  247.         jsr    _LVOModifyIDCMP(a6)    set new IDCMP values
  248.         bra.s    ClickDone
  249.  
  250. ; user clicked on a tile, move it if the chosen tile was a legal selection
  251. HandleLeft    movem.w    im_MouseX(a2),d0/d1    convert d0/d1 to tile x,y
  252.         subi.w    #9,d0            allow for border
  253.         bmi.s    ClickError        out of range
  254.         ext.l    d0
  255.         divs    #35,d0
  256.         cmpi.w    #4,d0
  257.         bge.s    ClickError
  258.  
  259.         subi.w    #39,d1            allow for offset to grid
  260.         bmi.s    ClickError        out of range
  261.         ext.l    d1
  262.         divs    #17,d1
  263.         cmpi.w    #4,d1
  264.         bge.s    ClickError
  265.  
  266.         bsr    MoveTiles        move correct tiles
  267.         subq.l    #1,Shuffles(a5)        subtract from shuffle count
  268.         bsr    ShuffleCount        and update it on the screen
  269.         bra.s    ClickDone
  270.  
  271. ClickError    bsr    Bleep            bleep display for error
  272.  
  273. ClickDone    movem.l    (sp)+,a2/a6
  274.         rts
  275.  
  276. ;==============================================================================
  277. ; ShuffleOnce()
  278. ;
  279. ; Performs one shuffle on the tiles and updates the display to reflect changes
  280. ;==============================================================================
  281. ShuffleOnce    moveq.l    #3,d0            figure which tile to move
  282.         bsr    Random
  283.         move.w    d0,-(sp)        and save it
  284.         moveq.l    #1,d0            now see if it's a row or col
  285.         and.l    Shuffles(a5),d0        columns on even iterations
  286.         beq.s    ShuffleColumn        we want to move up or down
  287.  
  288. ; execute this code when we are sliding the tiles left or right into the space
  289. ; the row number will be the same as the space but the column number can't be.
  290.         move.w    SpaceY(a5),d1        tile is in this row
  291.         move.w    (sp)+,d0        get the column number
  292.         cmp.w    SpaceX(a5),d0        is it the same
  293.         bne.s    DoShuffle        no, so it's valid now
  294.         addq.w    #1,d0            yes, so bump to the next tile
  295.         bra.s    DoShuffle        go move it
  296.  
  297. ; execute this code when we are sliding the tiles up or down into the space
  298. ; the column number will be the same as the space but the row number can't be.
  299. ShuffleColumn    move.w    SpaceX(a5),d0        tile is in this column
  300.         move.w    (sp)+,d1        get row number
  301.         cmp.w    SpaceY(a5),d1        is it the same
  302.         bne.s    DoShuffle        no, so it's valid now
  303.         addq.w    #1,d1            yes, so bump to the next tile
  304.  
  305. ; we have chosen the tile we want to move, update shuffle count and then call
  306. ; MoveTiles to move 1 or more tiles in the right direction (into the space)
  307. DoShuffle    bsr    MoveTiles        move relevant tiles
  308.         addq.l    #1,Shuffles(a5)        add one to number of shuffles
  309.         bsr    ShuffleCount        print current shufflecount
  310.         rts
  311.  
  312. ;==============================================================================
  313. ; Bleep()
  314. ;
  315. ; Just does a DisplayBeep on the screen this window is in
  316. ;==============================================================================
  317. Bleep        move.l    a6,-(sp)
  318.         movea.l    IntLib(a5),a6        using intuition
  319.         movea.l    MainWindow(a5),a0    find the screen to beep
  320.         movea.l    wd_WScreen(a0),a0
  321.         jsr    _LVODisplayBeep(a6)    do the flash
  322.         move.l    (sp)+,a6        and that's all
  323.         rts
  324.  
  325. ;==============================================================================
  326. ; ShuffleCount()
  327. ;
  328. ; Displays current number of shuffles in the top portion of the screen.
  329. ;==============================================================================
  330. ShuffleCount    movem.l    d2/d3/a6,-(sp)
  331.         movea.l    GfxLib(a5),a6        using graphics library
  332.  
  333.         movea.l    TheRastPort(a5),a1    set pen to background color
  334.         moveq.l    #0,d0
  335.         jsr    _LVOSetAPen(a6)
  336.  
  337.         moveq.l    #10,d0            erase the score area
  338.         moveq.l    #13,d1
  339.         moveq.l    #80,d2
  340.         moveq.l    #22,d3
  341.         movea.l    TheRastPort(a5),a1
  342.         jsr    _LVORectFill(a6)
  343.  
  344.         moveq.l    #15,d0            move to place for score
  345.         moveq.l    #20,d1
  346.         movea.l    TheRastPort(a5),a1
  347.         jsr    _LVOMove(a6)
  348.  
  349.         movea.l    TheRastPort(a5),a1    set pen to black
  350.         moveq.l    #2,d0
  351.         jsr    _LVOSetAPen(a6)
  352.  
  353.         movea.l    TheRastPort(a5),a1    and drawmode to jam1
  354.         moveq.l    #RP_JAM1,d0
  355.         jsr    _LVOSetDrMd(a6)
  356.  
  357.         movea.l    TextBuff(a5),a0
  358.         move.l    Shuffles(a5),d0        convert shuffles to ascii
  359.         bsr    bin2asc32        returns d0 = length
  360.         move.w    d0,-(sp)        save length for later
  361.         movea.l    TextBuff(a5),a0
  362.         movea.l    TheRastPort(a5),a1
  363.         jsr    _LVOText(a6)        write the text out
  364.  
  365.         movea.l    TheRastPort(a5),a1    set pen to white now
  366.         moveq.l    #1,d0
  367.         jsr    _LVOSetAPen(a6)
  368.  
  369.         moveq.l    #13,d0            move to place for score
  370.         moveq.l    #19,d1            offset it 2 in x and 1 in y
  371.         movea.l    TheRastPort(a5),a1
  372.         jsr    _LVOMove(a6)
  373.  
  374.         move.w    (sp)+,d0        get back the text length
  375.         movea.l    TextBuff(a5),a0        and the text buffer
  376.         movea.l    TheRastPort(a5),a1
  377.         jsr    _LVOText(a6)        write the text out
  378.  
  379.         movem.l    (sp)+,d2/d3/a6
  380.         rts
  381.  
  382. ;=============================================================================
  383. ; nextplace = bin2asc[nn]( value,buffer )
  384. ;   d0                 d0    a0
  385. ;
  386. ; converts the given binary value to a null terminated string of ascii digits
  387. ; in the buffer provided.  [nn] can be 08,16 or 32 to handle different sizes.
  388. ;============================================================================
  389. bin2asc08    ext.w    d0            make bytes into words
  390. bin2asc16    ext.l    d0            make words into a longwords
  391. bin2asc32    movem.l    d2/a2,-(sp)
  392.         movea.l    a0,a2            save buffer pointer
  393.         tst.l    d0            is number negative ?
  394.         bpl.s    bin2asc            nope, call main routine
  395.         neg.l    d0            yes, so make it positive
  396.         move.b    #'-',(a0)+        and output a minus sign
  397.  
  398. bin2asc        lea.l    PowersOfTen(pc),a1    point to powers of ten table
  399.  
  400. ; first we quickly check for the first real digit we will be using (non 0)
  401. 10$        move.l    (a1)+,d2        get next power of ten
  402.         beq.s    40$            value was zero to start
  403.         cmp.l    d2,d0            is the number this big ?
  404.         blt.s    10$            no, keep searching
  405.  
  406.         moveq.l    #'0',d1            current digit value
  407. 20$        addq.w    #1,d1            update this digit
  408.         sub.l    d2,d0            subtract current pwr of 10
  409. 30$        cmp.l    d2,d0            can we do it again ?
  410.         bge.s    20$            yes, keep going
  411.         move.b    d1,(a0)+        no, save the current digit
  412.         moveq.l    #'0',d1            digit value back to '0' now
  413.         move.l    (a1)+,d2        get next power of 10
  414.         bne.s    30$            and check against number
  415.         bra.s    50$            all done. terminate string
  416.  
  417. 40$        move.b    #'0',(a0)+        store an ascii 0
  418. 50$        clr.b    (a0)            terminate the string
  419.         move.l    a0,d0            compute length
  420.         sub.l    a2,d0
  421.         movem.l    (sp)+,d2/a2        and return
  422.         rts
  423.  
  424. PowersOfTen    DC.L    1000000000,100000000,10000000,1000000
  425.         DC.L    100000,10000,1000,100,10,1,0
  426.  
  427.  
  428. ;==============================================================================
  429. ; MoveTiles( xtile, ytile )
  430. ;          d0     d1
  431. ;
  432. ; Given a tile that was clicked on or a tile that was chosen by ShuffleOnce,
  433. ; moves the appropriate number of tiles towards the space and renders them.
  434. ;==============================================================================
  435. MoveTiles    movem.l    d2-d3,-(sp)
  436.         cmp.w    SpaceX(a5),d0        consistency check
  437.         bne.s    Check2            only row or column...
  438.         cmp.w    SpaceY(a5),d1        ...can be the same...
  439.         beq    MoveError        ...as the space
  440.         bra.s    MovingColumn        tiles are sliding up or down
  441.  
  442. Check2        cmp.w    SpaceY(a5),d1        but at least one of them...
  443.         bne.s    MoveError        ...must be the same
  444.  
  445. ; executes this code when we are sliding the tiles along a row into the space
  446.         moveq.l    #tile_SIZEOF,d2        array increment when moving
  447.         move.w    d0,d3            see how many to move
  448.         sub.w    SpaceX(a5),d3
  449.         bpl.s    DoMove
  450.         neg.w    d2            have to go backwards
  451.         neg.w    d3
  452.         bra.s    DoMove
  453.  
  454. ; executes this code when we are sliding the tiles up or down into the space
  455. MovingColumn    moveq.l    #4*tile_SIZEOF,d2    array increment when moving
  456.         move.w    d1,d3            see how many tiles to move
  457.         sub.w    SpaceY(a5),d3
  458.         bpl.s    DoMove
  459.         neg.w    d2            have to go backwards
  460.         neg.w    d3
  461.  
  462. ; gets here with d2 containing the array increment for moving from one tile
  463. ; to the next and d3 containing the number of tiles affected ( 1 to 3 tiles)
  464. ; first, we set up a0 pointing to the tile that contains the space.
  465. DoMove        movem.w    d0/d1,-(sp)        save tile that becomes space
  466.         movem.w    SpaceX(a5),d0/d1    we start from the space
  467.         mulu.w    #tile_SIZEOF,d0        get tile x array position
  468.         mulu.w    #4*tile_SIZEOF,d1    get tile y array position
  469.         add.l    d1,d0            d0 = offset into array
  470.         movea.l    GameArray(a5),a0
  471.         adda.l    d0,a0            a0 points to the space tile
  472.         subq.w    #1,d3            fix up count for dbra
  473.  
  474. MoveNextTile    move.b    t_type(a0,d2.w),t_type(a0)    slide a tile into space
  475.         move.w    #1,t_moved(a0)        mark this one as changed
  476.         lea.l    0(a0,d2.w),a0        move to the other tile
  477.         dbra    d3,MoveNextTile        and carry on if more
  478.         clr.b    t_type(a0)        now mark this one as the space
  479.         move.w    #1,t_moved(a0)        and mark it as moved
  480.  
  481.         move.l    (sp)+,SpaceX(a5)    set up the new space
  482.         bsr    DrawMovedTiles        re-draw the ones that moved
  483.         bra.s    MoveComplete
  484. MoveError    bsr    Bleep            beep display for errors
  485. MoveComplete    movem.l    (sp)+,d2-d3
  486.         rts
  487.  
  488. ;==============================================================================
  489. ; DrawBorder()
  490. ;
  491. ; Draws the border around the playing area.
  492. ;==============================================================================
  493. DrawBorder    movem.l    d2-d6,-(sp)
  494.         movea.l    MainWindow(a5),a0    get pointer to a window
  495.         moveq.l    #0,d0            x start
  496.         move.w    wd_Height(a0),d1    y start
  497.         subi.w    #75,d1
  498.         move.w    wd_Width(a0),d2        width
  499.         moveq.l    #75,d3            height
  500.         moveq.l    #1,d4            border color
  501.         moveq.l    #0,d5            middle color
  502.         moveq.l    #3,d6            border width
  503.         bsr    SpecialBox
  504.         movem.l    (sp)+,d2-d6
  505.         rts
  506.  
  507. ;==============================================================================
  508. ; InitTiles()
  509. ;
  510. ; Initialises the tile array with tile positions and letters to go in them.
  511. ;==============================================================================
  512. InitTiles    movem.l    d2-d3/a2,-(sp)
  513.         movea.l    GameArray(a5),a0    a0 points to tile data
  514.         lea.l    15*tile_SIZEOF(a0),a0    point to the last tile
  515.         lea.l    Letters(pc),a1        a1 points to current letter
  516.         movea.l    MainWindow(a5),a2
  517.         moveq.l    #3,d3            row counter
  518.         move.w    d3,SpaceX(a5)        this is where the space is
  519.         move.w    d3,SpaceY(a5)        when we initialise
  520. NextRow        moveq.l    #3,d2            column counter
  521. NextColumn    move.w    d2,d0            x pos = col*35+9
  522.         mulu.w    #35,d0
  523.         addi.w    #9,d0
  524.         move.w    d0,t_x(a0)
  525.         move.w    d3,d0            y pos = row*17+4
  526.         mulu.w    #17,d0
  527.         addq.w    #4,d0
  528.         subi.w    #75,d0            ypos += wd_Height-75
  529.         add.w    wd_Height(a2),d0
  530.         move.w    d0,t_y(a0)
  531.         move.b    (a1)+,t_type(a0)    fill in the letter
  532.         lea.l    -tile_SIZEOF(a0),a0    point to previous tile
  533.         dbra    d2,NextColumn
  534.         dbra    d3,NextRow
  535.         movem.l    (sp)+,d2-d3/a2
  536.         rts
  537.  
  538. ;==============================================================================
  539. ; DrawAllTiles()
  540. ;
  541. ; refreshes tile display by marking all tiles as moved and calls DrawMovedTiles
  542. ;==============================================================================
  543. DrawAllTiles    movea.l    GameArray(a5),a0    get to first tile
  544.         moveq.l    #15,d0            doing 16 of them
  545. 10$        move.w    #1,t_moved(a0)        mark this one as moved
  546.         lea.l    tile_SIZEOF(a0),a0    move to next tile
  547.         dbra    d0,10$            drop through to DrawMovedTiles
  548.  
  549. ;==============================================================================
  550. ; DrawMovedTiles()
  551. ;
  552. ; Redraws any tiles that have a non-zero t_moved field and then clears it.
  553. ;==============================================================================
  554. DrawMovedTiles    movem.l    d2/a2,-(sp)
  555.         movea.l    GameArray(a5),a2    point to first tile
  556.         moveq.l    #15,d2            have to check all of them
  557. 10$        tst.w    t_moved(a2)        was this tile moved
  558.         beq.s    20$            no, so no work
  559.         movea.l    a2,a0            yes, so draw it
  560.         bsr.s    DrawTile
  561.         clr.w    t_moved(a2)        mark as not moved now
  562. 20$        lea.l    tile_SIZEOF(a2),a2    point to next tile
  563.         dbra    d2,10$            and carry on
  564.         movem.l    (sp)+,d2/a2
  565.         rts
  566.  
  567. ;==============================================================================
  568. ; DrawTile( tile )
  569. ;         a0
  570. ;
  571. ; Draws a tile based on its array position and the letter assigned to that tile
  572. ;==============================================================================
  573. DrawTile    movem.l    d2-d6/a2/a6,-(sp)
  574.         movea.l    a0,a2            stash tile address
  575.         movem.w    t_x(a2),d0/d1        get tile start position
  576.         moveq.l    #32,d2            tile is this wide
  577.         moveq.l    #16,d3            and this high
  578.         moveq.l    #3,d4            assume a colored tile
  579.         moveq.l    #2,d5
  580.         moveq.l    #1,d6            border width is 1
  581.         tst.b    t_type(a2)        is this the blank tile ?
  582.         bne.s    10$            no
  583.         moveq.l    #0,d4            just do background color...
  584.         moveq.l    #0,d5            ...for the blank tile
  585. 10$        bsr    SpecialBox
  586.         tst.b    t_type(a2)        is this the blank tile ?
  587.         beq.s    TileDrawn        yes, no more work to do
  588.  
  589.         movea.l    GfxLib(a5),a6        using graphics library
  590.         moveq.l    #1,d0            set pen to white
  591.         movea.l    TheRastPort(a5),a1
  592.         jsr    _LVOSetAPen(a6)
  593.  
  594.         moveq.l    #RP_JAM1,d0        only jam 1 color for text
  595.         movea.l    TheRastPort(a5),a1
  596.         jsr    _LVOSetDrMd(a6)
  597.  
  598.         movem.w    t_x(a2),d0/d1        get position to move to
  599.         addi.w    #12,d0            add offset for letters
  600.         addi.w    #10,d1
  601.         jsr    _LVOMove(a6)
  602.  
  603.         lea.l    t_type(a2),a0        address of string
  604.         movea.l    TheRastPort(a5),a1    to this rastport
  605.         moveq.l    #1,d0            drawing 1 character
  606.         jsr    _LVOText(a6)
  607.  
  608. TileDrawn    movem.l    (sp)+,d2-d6/a2/a6
  609.         rts
  610.  
  611. ;==============================================================================
  612. ; SpecialBox( left, top, width, height, bordercolor, boxcolor, thickness)
  613. ;           d0    d1       d2      d3        d4        d5      d6
  614. ;
  615. ; Draws a filled in box with a border of the required thickness using the
  616. ; specified colors.  The thickness is doubled in the x direction so that
  617. ; the border is the same physical width all the way around.  As with the
  618. ; RectFill function, xmin<=xmax and ymin<=ymax.
  619. ;==============================================================================
  620. SpecialBox    movem.l    d2-d3/d6/a6,-(sp)
  621.         movea.l    GfxLib(a5),a6        using graphics library
  622.         subq.w    #1,d2            convert width and height...
  623.         subq.w    #1,d3            ...to absolute co-ordinates
  624.         add.w    d0,d2
  625.         add.w    d1,d3
  626.         movem.w    d0-d3,-(sp)        save the box co-ordinates
  627.  
  628.         movea.l    TheRastPort(a5),a1
  629.         move.w    d4,d0            set pen to border color
  630.         jsr    _LVOSetAPen(a6)
  631.         movem.w    (sp),d0-d3        get box parameters
  632.         movea.l    TheRastPort(a5),a1    and draw it
  633.         jsr    _LVORectFill(a6)
  634.  
  635.         movea.l    TheRastPort(a5),a1
  636.         move.w    d5,d0            set pen to middle color
  637.         jsr    _LVOSetAPen(a6)
  638.         movem.w    (sp)+,d0-d3        get old box co-ordinates
  639.         add.w    d6,d1            ymin += thickness
  640.         sub.w    d6,d3            ymax -= thickness
  641.         asl.w    #1,d6            double thickness in x
  642.         add.w    d6,d0            xmin += thickness*2
  643.         sub.w    d6,d2            xmax -= thickness*2
  644.         movea.l    TheRastPort(a5),a1    and draw it
  645.         jsr    _LVORectFill(a6)
  646.  
  647.         movem.l    (sp)+,d2-d3/d6/a6
  648.         rts
  649.  
  650. ;==============================================================================
  651. ; RndNum = Random( UpperLimit )
  652. ;   d0              d0
  653. ;
  654. ; returns a random integer in the range 0 to UpperLimit-1
  655. ;============================================================================
  656. Random        move.w    d0,-(sp)    save range
  657.         beq.s    10$        range of 0 returns 0 always
  658.         bsr.s    LongRnd        get a longword random number
  659.         clr.w    d0        use upper word (it's most random)
  660.         swap    d0
  661.         divu.w    (sp),d0        divide by range...
  662.         clr.w    d0
  663.         swap    d0        ...and use remainder for the result
  664. 10$        addq.l    #2,sp        scrap range on stack
  665.         rts
  666.  
  667. ; this is the main random number generation routine. Not user callable
  668. LongRnd        movem.l    d2-d3,-(sp)    
  669.         movem.l    RND(a5),d0/d1    D0=LSB's, D1=MSB's of random number
  670.         andi.b    #$0e,d0        ensure upper 59 bits are an...
  671.         ori.b    #$20,d0        ...odd binary number
  672.         move.l    d0,d2
  673.         move.l    d1,d3
  674.         add.l    d2,d2        accounts for 1 of 17 left shifts
  675.         addx.l    d3,d3        [D2/D3] = RND*2
  676.         add.l    d2,d0
  677.         addx.l    d3,d1        [D0/D1] = RND*3
  678.         swap    d3        shift [D2/D3] additional 16 times
  679.         swap    d2
  680.         move.w    d2,d3
  681.         clr.w    d2
  682.         add.l    d2,d0        add to [D0/D1]
  683.         addx.l    d3,d1
  684.         movem.l    d0/d1,RND(a5)    save for next time through
  685.         move.l    d1,d0        most random part to D0
  686.         movem.l    (sp)+,d2-d3
  687.         rts
  688.  
  689. ;==============================================================================
  690. ; Success = OpenLibs( libtable )
  691. ;   d0             a0
  692. ;==============================================================================
  693. OpenLibs    movem.l    a2-a3/a6,-(sp)
  694.         movea.l    SysLib(a5),a6        using exec library
  695.         movea.l    a0,a2            save working libtable ptr
  696.         movea.l    a0,a3            a3 used to calculate name addr
  697.  
  698. 10$        moveq.l    #0,d0            get the version
  699.         move.w    (a2)+,d0
  700.         bmi.s    LibsOpened        return TRUE
  701.         move.w    (a2)+,d1        get offset to name
  702.         lea.l    0(a3,d1.w),a1        addr of name in a1
  703.         jsr    _LVOOpenLibrary(a6)    open the lib
  704.         move.w    (a2)+,d1        offset to store at
  705.         move.l    d0,0(a5,d1.w)        save in global table
  706.         bne.s    10$            OK, go for the next
  707. LibsOpened    movem.l    (sp)+,a2-a3/a6        could return 0 if failed above
  708.         rts        
  709.  
  710. ;==============================================================================
  711. ; CloseLibs( libtable )
  712. ;        a0
  713. ;==============================================================================
  714. CloseLibs    movem.l    a2/a6,-(sp)
  715.         movea.l    SysLib(a5),a6        using exec library
  716.         movea.l    a0,a2            save libtable pointer
  717.  
  718. 10$        tst.w    (a2)+            end of list ?
  719.         bmi.s    LibsClosed        yes, quit now
  720.         move.l    (a2)+,d0        offset to lower word
  721.         move.l    0(a5,d0.w),d0        get lib pointer
  722.         beq.s    LibsClosed        that's it, this one failed
  723.         movea.l    d0,a1
  724.         jsr    _LVOCloseLibrary(a6)    close this library
  725.         bra.s    10$            and go for the next
  726. LibsClosed    movem.l    (sp)+,a2/a6
  727.         rts
  728.  
  729. ;==============================================================================
  730. ; Success = AllocMemory( memtable )
  731. ;   d0                a0
  732. ;==============================================================================
  733. AllocMemory    movem.l    a2/a6,-(sp)
  734.         movea.l    SysLib(a5),a6        using exec library
  735.         movea.l    a0,a2            stash memtable address
  736.  
  737. 10$        move.l    (a2)+,d0        get size
  738.         bmi.s    MemAlloced        last entry, return true
  739.         moveq.l    #0,d1
  740.         move.w    (a2)+,d1        get type
  741.         bset.l    #MEMB_CLEAR,d1        clear it too
  742.         jsr    _LVOAllocMem(a6)    allocate it
  743.         move.w    (a2)+,d1        get store offset
  744.         move.l    d0,0(a5,d1.w)        save it
  745.         bne.s    10$            OK, memory fetched
  746. MemAlloced    movem.l    (sp)+,a2/a6        could return 0 if it failed
  747.         rts
  748.  
  749. ;==============================================================================
  750. ; FreeMemory( memtable )
  751. ;         a0
  752. ;==============================================================================
  753. FreeMemory    movem.l    a2/a6,-(sp)
  754.         movea.l    SysLib(a5),a6        using exec library
  755.         movea.l    a0,a2            stash table pointer
  756.  
  757. 10$        move.l    (a2)+,d0        end of list
  758.         bmi.s    MemFreed        yep, exit now
  759.         move.l    (a2)+,d1        offset to lower word
  760.         move.l    0(a5,d1.w),d1        get pointer
  761.         beq.s    MemFreed        quit! alloc failed on this one
  762.         movea.l    d1,a1
  763.         jsr    _LVOFreeMem(a6)
  764.         bra.s    10$
  765. MemFreed    movem.l    (sp)+,a2/a6
  766.         rts
  767.  
  768. ;==============================================================================
  769. ; List of libraries required to run this little demonstration program
  770. ;==============================================================================
  771. Libraries    DC.W    33,IntName-Libraries,IntLib
  772.         DC.W    33,GfxName-Libraries,GfxLib
  773.         DC.W    33,DosName-Libraries,DosLib
  774.         DC.W    -1
  775. IntName        DC.B    'intuition.library',0
  776.         CNOP    0,2
  777. GfxName        DC.B    'graphics.library',0
  778.         CNOP    0,2
  779. DosName        DC.B    'dos.library',0
  780.         CNOP    0,2
  781.  
  782. ;==============================================================================
  783. ; list of memory requirements to run the demonstration program
  784. ;==============================================================================
  785. MemTable    DC.L    16*tile_SIZEOF,(MEMF_PUBLIC<<16)+GameArray
  786.         DC.L    80,(MEMF_PUBLIC<<16)+TextBuff
  787.         DC.L    -1
  788.  
  789. ;==============================================================================
  790. ; The new window definition for the window that this program will run in
  791. ;==============================================================================
  792. WINDOWFLAGS SET WINDOWDEPTH!WINDOWCLOSE!WINDOWDRAG!SIMPLE_REFRESH!ACTIVATE
  793. WINDOWFLAGS SET WINDOWFLAGS!RMBTRAP
  794.  
  795. IDCMPFLAGS EQU CLOSEWINDOW!REFRESHWINDOW!MOUSEBUTTONS
  796.  
  797. MyWindow    DC.W    0,0,155,110    left,top,width,height
  798.         DC.B    2,1        detailpen,blockpen
  799.         DC.L    IDCMPFLAGS
  800.         DC.L     WINDOWFLAGS
  801.         DC.L    0        Gadgets-MyWindow
  802.         DC.L    0        no checkmark
  803.         DC.L    Title-MyWindow    relative ref to title
  804.         DC.L    0        no screen
  805.         DC.L    0        no bitmap
  806.         DC.W    0,0,0,0        no min or max sizes
  807.         DC.W    WBENCHSCREEN    where this window lives
  808.  
  809. Title        DC.B    'Slider    ',0
  810.         CNOP    0,2
  811. Letters        DC.B    0,'ONMLKJIHGFEDCBA'    easier init like this
  812.         CNOP    0,2
  813.  
  814.         END
  815.  
  816.